#pragma once

#include <boost/asio.hpp>
#include <boost/noncopyable.hpp>

using boost::asio::ip::tcp;

namespace AlgoTrading
{
	namespace ConnectionLibrary
	{

		class handler_allocator
			: private boost::noncopyable
		{
		public:
			handler_allocator();
			void* allocate(std::size_t size);
			void deallocate(void* pointer);
		};

		template <typename Handler>
		class custom_alloc_handler
		{
		public:
			custom_alloc_handler(handler_allocator& a, Handler h)
				: allocator(a),
				handler(h)
			{
			}

			template <typename Arg1>
			void operator()(Arg1 arg1)
			{
				handler(arg1);
			}

			template <typename Arg1, typename Arg2>
			void operator()(Arg1 arg1, Arg2 arg2)
			{
				handler(arg1, arg2);
			}

			friend void* asio_handler_allocate(std::size_t size, custom_alloc_handler<Handler>* this_handler)
			{
				return this_handler->allocator.allocate(size);
			}

			friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/, custom_alloc_handler<Handler>* this_handler)
			{
				this_handler->allocator.deallocate(pointer);
			}

		private:
			handler_allocator& allocator;
			Handler handler;
		};

		// Helper function to wrap a handler object to add custom allocation.
		template <typename Handler>
		inline custom_alloc_handler<Handler> make_custom_alloc_handler(
			handler_allocator& a, Handler h)
		{
			return custom_alloc_handler<Handler>(a, h);
		}
	}
}